
import IPoint from "./interface/IPoint"
import TWEEN from "@tweenjs/tween.js";

/**
 * 获取鼠标点击后相对于canvas左上角的坐标
 * @param myCanvas 
 * @param e 
 * @returns 
 */
function getMousePos(myCanvas: HTMLCanvasElement, e: MouseEvent | IPoint): IPoint {
    let downX: number;
    let downY: number;
    if (e.x && e.y) {
        downX = e.x;
        downY = e.y;
    } else {
        downX = e.clientX;
        downY = e.clientY;
    }

    let { left, top } = myCanvas.getBoundingClientRect();

    let xDist = downX - left;
    let yDist = downY - top;

    return {
        x: xDist,
        y: yDist,
    };
}

/**
 * 检查点point是否在矩形内
 */
function isPointInRect(block: any, point: IPoint) {
    let { x, y, width, height } = block;
    let { x: x1, y: y1 } = point;
    return (x <= x1 && x1 <= x + width) && (y <= y1 && y1 <= y + height);
}

/**
  * 判断点是否在旋转后的矩形中
  * @param point 触摸点的坐标
  * @param node 碰撞节点，锚点必须为(0.5,0.5)
  */
function isPosInRotationRect(node: any, point: IPoint, center: IPoint, angle: number) {
    let hw = node.width / 2;
    let hh = node.height / 2
    let X = point.x
    let Y = point.y
    let r = -angle * (Math.PI / 180)
    let nTempX = center.x + (X - center.x) * Math.cos(r) - (Y - center.y) * Math.sin(r);
    let nTempY = center.y + (X - center.x) * Math.sin(r) + (Y - center.y) * Math.cos(r);
    if (nTempX > center.x - hw && nTempX < center.x + hw && nTempY > center.y - hh && nTempY < center.y + hh) {
        return true;
    }
    return false
}

/**
 * 生成唯一id
 * @returns 
 */
function getUuid(): string {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v
            = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16);
    });
}

var timer: number;
// 过渡变化数值
function runAnimate(start: any, end: any, duration: number, fn: Function, cancel: boolean = true) {
    cancelAnimationFrame(timer)
    animate();
    var tween = new TWEEN.Tween(start)
        .to(end, duration)
        .onStart(() => { })
        .onUpdate((e) => {
            fn && fn(e);
        })
        .onComplete((e) => {
            timer && cancelAnimationFrame(timer);
        })
        .easing(TWEEN.Easing.Quadratic.Out)
        .start();

    function animate() {
        timer = requestAnimationFrame(animate);
        TWEEN.update();
    }

}

/**
 * 一个点相对另一个点旋转后的坐标
 * @param point // 要旋转的点
 * @param originPoint // 相对的原点,不动的点
 * @param angle // 旋转的角度
 * @returns 
 */
function getRotatePoint(point: IPoint, originPoint: IPoint = { x: 0, y: 0 }, angle: number) {
    const cosA = Math.cos(angle * Math.PI / 180);
    const sinA = Math.sin(angle * Math.PI / 180);
    const rx = originPoint.x + (point.x - originPoint.x) * cosA - (point.y - originPoint.y) * sinA;
    const ry = originPoint.y + (point.x - originPoint.x) * sinA + (point.y - originPoint.y) * cosA;
    return { x: rx, y: ry };
}

/**
 * 三次贝赛尔曲线, 两个控制点
 * @param t // 第几段,
 * @param p0 // 起始点
 * @param p1 // 控制点1
 * @param p2 // 控制点2
 * @param p3 // 终点
 * @returns 
 */
function calculateBezierPointForCubic(t: number, p0: IPoint, p1: IPoint, p2: IPoint, p3: IPoint): IPoint {
    var point: IPoint = { x: 0, y: 0 };
    var temp = 1 - t;
    point.x = p0.x * temp * temp * temp + 3 * p1.x * t * temp * temp + 3 * p2.x * t * t * temp + p3.x * t * t * t;
    point.y = p0.y * temp * temp * temp + 3 * p1.y * t * temp * temp + 3 * p2.y * t * t * temp + p3.y * t * t * t;
    return point;
}

/**
 * 点与线的最短距离
 * @param x 点
 * @param y 
 * @param x1 两点连成的线
 * @param y1 
 * @param x2 
 * @param y2 
 * @returns 
 */
function distanceOfPoint2Line(x: number, y: number, x1: number, y1: number, x2: number, y2: number) {
    var A = x - x1;
    var B = y - y1;
    var C = x2 - x1;
    var D = y2 - y1;

    var dot = A * C + B * D;
    var len_sq = C * C + D * D;
    var param = -1;
    if (len_sq != 0) //线段长度不能为0
        param = dot / len_sq;

    var xx, yy;

    if (param < 0) {
        xx = x1;
        yy = y1;
    }
    else if (param > 1) {
        xx = x2;
        yy = y2;
    }
    else {
        xx = x1 + param * C;
        yy = y1 + param * D;
    }

    var dx = x - xx;
    var dy = y - yy;
    return Math.sqrt(dx * dx + dy * dy);
}

function getMinDistLine(point: IPoint, lines: any[]) {
    if (lines.length <= 0) return;
    let dists: number[] = []
    lines.forEach(item => {
        let xdist1 = item[0].x - point.x;
        let ydist1 = item[0].y - point.y;

        let xdist2 = item[1].x - point.x;
        let ydist2 = item[1].y - point.y;

        dists.push(Math.sqrt(xdist1 * xdist1 + ydist1 * ydist1) + Math.sqrt(xdist2 * xdist2 + ydist2 * ydist2));
    })

    let minDist = Math.min(...dists);
    let index = dists.findIndex(item => item == minDist)
    return lines[index]
}

//点P到线段AB的距离
//使用矢量算法，计算线AP在线段AB方向上的投影
function point2SegDist(point: IPoint, point1: IPoint, point2: IPoint) {
    let x = point.x, x1 = point1.x, x2 = point2.x
    let y = point.y, y1 = point1.y, y2 = point2.y

    //线段AB 为一个点
    if (x1 == x2 && y1 == y2) return {
        type: true,
        point: point1,
        dist: 0
    }

    let cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1);
    let d2 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
    //r = 0 垂足为point1  r = 1 垂足为point2
    let r = cross / d2;
    let px = x1 + (x2 - x1) * r;
    let py = y1 + (y2 - y1) * r;
    return {
        type: r >= 0 && r <= 1, //true  垂足在线段内   false 垂足在线段外
        point: { x: px, y: py },
        dist: Math.sqrt((x - px) * (x - px) + (py - y) * (py - y))
    };
}

// 根据两点获取向量
function getVector(point1: IPoint, point2: IPoint) {
    return {
        x: point1.x - point2.x,
        y: point1.y - point2.y
    }
}

function crossMul(point1: IPoint, point2: IPoint) {
    return point1.x * point2.y - point1.y * point2.x;
}

// 获取向量的长度
function getVectorLength(vector: IPoint) {
    return Math.sqrt(vector.x * vector.x + vector.y * vector.y)
}

// 获取线段的中点
function getVectorCenter(point1: IPoint, point2: IPoint) {
    return {
        x: (point1.x + point2.x) / 2,
        y: (point1.y + point2.y) / 2
    }
}

//  求两个向量之间的夹角
function get2vectorAngle(vector1: IPoint, vector2: IPoint) {
    var angle = Math.atan2(vector2.y, vector2.x) - Math.atan2(vector1.y, vector1.x);
    // if (angle < 0) angle += 2 * Math.PI;
    return angle;
}

function getCenterPoint(point1: IPoint, point2: IPoint): IPoint {
    return {
        x: (point2.x + point1.x) / 2,
        y: (point2.y + point1.y) / 2
    }
}

// 16进制转rgb
function hex2Rgba(hex: string, opacity: number) {
    if (!hex) hex = '#ededed';
    let rgba = 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' +
        parseInt('0x' + hex.slice(3, 5)) + ',' +
        parseInt('0x' + hex.slice(5, 7)) + ',' +
        (opacity || "1") + ')'
    return rgba
}

// rgba转16进制
function rgb2Hex(rgb: string) {
    if (!rgb) rgb = 'rgb(237,237,237)'
    var regexp = /[0-9]{0,3}/g
    var res = rgb.match(regexp) // 利用正则表达式去掉多余的部分，将rgb中的数字提取
    var hexRes = '#'
    var hex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
    var hexArr = []
    for (let i = 0; i < res.length; i++) {
        if (res[i]) {
            if (res[i] > 16) {
                let leftIndex = (res[i] / 16) >> 0 // 向下取整
                let rightIndex = +res[i] % 16
                hexArr.push(hex[leftIndex])
                hexArr.push(hex[rightIndex])
            } else {
                hexArr.push(0)
                hexArr.push(hex[res[i]])
            }
        }
    }
    return hexRes += hexArr.join('')  // #EDEDED
}

function getRandomChineseWord () {
    var _rsl = "";
    var _randomUniCode = Math.floor(Math.random() * (40870 - 19968) + 19968).toString(16);
    eval("_rsl=" + '"\\u' + _randomUniCode + '"');
    return _rsl;
}

export {
    getMousePos,
    isPointInRect,
    getUuid,
    runAnimate,
    getRotatePoint,
    isPosInRotationRect,
    calculateBezierPointForCubic,
    distanceOfPoint2Line,
    getMinDistLine,
    getVectorLength,
    getVectorCenter,
    get2vectorAngle,
    point2SegDist,
    getVector,
    crossMul,
    getCenterPoint,
    hex2Rgba,
    rgb2Hex,
    getRandomChineseWord,
}